// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//
#pragma once

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>

#include <pollux/functions/macros.h>
#include <pollux/functions/registerer.h>
#include <pollux/functions/prestosql/types/uuid_registration.h>
#include <pollux/functions/prestosql/types/uuid_type.h>

namespace kumo::pollux::functions {
#define POLLUX_GEN_BINARY_EXPR_UUID(Name, uuidCompExpr)                         \
  template <typename T>                                                        \
  struct Name##Uuid {                                                          \
    POLLUX_DEFINE_FUNCTION_TYPES(T);                                            \
                                                                               \
    MELON_ALWAYS_INLINE void                                                   \
    call(bool& result, const arg_type<Uuid>& lhs, const arg_type<Uuid>& rhs) { \
      result = (uuidCompExpr);                                                 \
    }                                                                          \
  };

    POLLUX_GEN_BINARY_EXPR_UUID(LtFunction, (uint128_t)lhs < (uint128_t)rhs);

    POLLUX_GEN_BINARY_EXPR_UUID(GtFunction, (uint128_t)lhs > (uint128_t)rhs);

    POLLUX_GEN_BINARY_EXPR_UUID(LteFunction, (uint128_t)lhs <= (uint128_t)rhs);

    POLLUX_GEN_BINARY_EXPR_UUID(GteFunction, (uint128_t)lhs >= (uint128_t)rhs);

#undef POLLUX_GEN_BINARY_EXPR_UUID

    template<typename T>
    struct BetweenFunctionUuid {
        POLLUX_DEFINE_FUNCTION_TYPES(T);

        MELON_ALWAYS_INLINE void call(
            bool &result,
            const arg_type<Uuid> &value,
            const arg_type<Uuid> &low,
            const arg_type<Uuid> &high) {
            auto castValue = static_cast<uint128_t>(value);
            result = castValue >= static_cast<uint128_t>(low) &&
                     castValue <= static_cast<uint128_t>(high);
        }
    };

    template<typename T>
    struct UuidFunction {
        POLLUX_DEFINE_FUNCTION_TYPES(T);

        static constexpr bool is_deterministic = false;

        MELON_ALWAYS_INLINE void call(int128_t &result) {
            boost::uuids::uuid uuid = generator_();
            memcpy(&result, uuid.data, 16);
        }

    private:
        boost::uuids::random_generator generator_;
    };

    inline void registerUuidFunctions(const std::string &prefix) {
        registerUuidType();
        register_function<UuidFunction, Uuid>({prefix + "uuid"});
        register_function<LtFunctionUuid, bool, Uuid, Uuid>({prefix + "lt"});
        register_function<GtFunctionUuid, bool, Uuid, Uuid>({prefix + "gt"});
        register_function<LteFunctionUuid, bool, Uuid, Uuid>({prefix + "lte"});
        register_function<GteFunctionUuid, bool, Uuid, Uuid>({prefix + "gte"});
        register_function<BetweenFunctionUuid, bool, Uuid, Uuid, Uuid>(
            {prefix + "between"});
    }
} // namespace kumo::pollux::functions
